home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / inetray / sendrpc.c < prev    next >
C/C++ Source or Header  |  1993-08-15  |  15KB  |  556 lines

  1. /*======================================================================
  2.                     S E N D R P C . C 
  3.                     doc: Thu May  7 16:55:29 1992
  4.                     dlm: Fri Jul 23 16:31:44 1993
  5.                     (c) 1992 ant@ips.id.ethz.ch
  6.                     uE-Info: 66 57 T 0 0 72 2 2 8 ofnI
  7. ======================================================================*/
  8.  
  9. /*
  10.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  11.  * unrestricted use provided that this legend is included on all tape
  12.  * media and as a part of the software program in whole or part.  Users
  13.  * may copy or modify Sun RPC without charge, but are not authorized
  14.  * to license or distribute it to anyone else except as part of a product or
  15.  * program developed by the user.
  16.  * 
  17.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  18.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  19.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  20.  * 
  21.  * Sun RPC is provided with no support and without any obligation on the
  22.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  23.  * modification or enhancement.
  24.  * 
  25.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  26.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  27.  * OR ANY PART THEREOF.
  28.  * 
  29.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  30.  * or profits or other special, indirect and consequential damages, even if
  31.  * Sun has been advised of the possibility of such damages.
  32.  * 
  33.  * Sun Microsystems, Inc.
  34.  * 2550 Garcia Avenue
  35.  * Mountain View, California  94043
  36.  */
  37.  
  38. /*
  39.    This file implements the function sendrpc(), which is an enhanced
  40.    version of the callrpc() routine. The source has been taken out of
  41.    the following SUN RPC 4.0 files:
  42.        pmap_getport.c
  43.        clnt_udp.c
  44.        clnt_simple.c
  45.  
  46.    Note that a lot of code has been replicated to make this work!
  47.        
  48.    sendrpc() behaves much like callrpc() with the following exceptions:
  49.        - when finding a port number (getport) the timeout supplied in
  50.          the external variable sendrpc_timeout is taken (instead of
  51.          the default 60 seconds).
  52.     - return is immediate (independently of out and outproc which
  53.       are dummies)
  54.     - the ascii-form of inet addresses are accepted (not only the
  55.           names)
  56.  
  57. */
  58.  
  59. #include <stdio.h>
  60. #include <errno.h>
  61. #include <rpc/rpc.h>
  62. #include <rpc/pmap_prot.h>
  63. #include <rpc/pmap_clnt.h>
  64. #include <sys/socket.h>
  65. #include <sys/ioctl.h>
  66. #ifndef FIONBIO                /* Solaris 2.2 */
  67. #include <sys/filio.h>
  68. #endif
  69. #include <net/if.h>
  70. #include <netdb.h>        /* Prefer system over rpc/netdb.h */
  71. #include <string.h>
  72. #ifndef ITIMER_REAL
  73. #include     <sys/time.h>
  74. #endif
  75.  
  76. int sendrpc_timeout = 13;        /* Default timeout */
  77.  
  78. static u_short sendrpc_getport(address, program, version, protocol)
  79.     struct sockaddr_in *address;
  80.     u_long program;
  81.     u_long version;
  82.     u_int protocol;
  83. {
  84.     u_short port = 0;
  85.     int socket = -1;
  86.     register CLIENT *client;
  87.     struct pmap parms;
  88.     struct timeval tottimeout;
  89.     struct timeval timeout;
  90.  
  91.     tottimeout.tv_sec = sendrpc_timeout;
  92.     timeout.tv_sec = 5;
  93.     tottimeout.tv_usec = timeout.tv_usec = 0;
  94.     
  95.     address->sin_port = htons(PMAPPORT);
  96.     client = clntudp_bufcreate(address, PMAPPROG,
  97.         PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
  98.     if (client != (CLIENT *)NULL) {
  99.         parms.pm_prog = program;
  100.         parms.pm_vers = version;
  101.         parms.pm_prot = protocol;
  102.         parms.pm_port = 0;  /* not needed or used */
  103.         if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
  104.             xdr_u_short, &port, tottimeout) != RPC_SUCCESS){
  105.             rpc_createerr.cf_stat = RPC_PMAPFAILURE;
  106.             clnt_geterr(client, &rpc_createerr.cf_error);
  107.         } else if (port == 0) {
  108.             rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
  109.         }
  110.         CLNT_DESTROY(client);
  111.     }
  112.     (void)close(socket);
  113.     address->sin_port = 0;
  114.     return (port);
  115. }
  116.  
  117. /* 
  118.  * Private data kept per client handle
  119.  */
  120. static struct cu_data {
  121.     int           cu_sock;
  122.     bool_t           cu_closeit;
  123.     struct sockaddr_in cu_raddr;
  124.     int           cu_rlen;
  125.     struct timeval       cu_wait;
  126.     struct timeval     cu_total;
  127.     struct rpc_err       cu_error;
  128.     XDR           cu_outxdrs;
  129.     u_int           cu_xdrpos;
  130.     u_int           cu_sendsz;
  131.     char           *cu_outbuf;
  132.     u_int           cu_recvsz;
  133.     char           cu_inbuf[1];
  134. };
  135.  
  136. extern int errno;
  137.  
  138. /*
  139.  * UDP bases client side rpc operations
  140.  */
  141. static enum clnt_stat    clntudp_call();
  142. static void        clntudp_abort();
  143. static void        clntudp_geterr();
  144. static bool_t        clntudp_freeres();
  145. static bool_t           clntudp_control();
  146. static void        clntudp_destroy();
  147.  
  148. static struct clnt_ops udp_ops = {
  149.     clntudp_call, 
  150.     clntudp_abort, 
  151.     clntudp_geterr,
  152.     clntudp_freeres,
  153.     clntudp_destroy,
  154.     clntudp_control
  155. };
  156.  
  157. static enum clnt_stat 
  158. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
  159.     register CLIENT    *cl;        /* client handle */
  160.     u_long        proc;        /* procedure number */
  161.     xdrproc_t    xargs;        /* xdr routine for args */
  162.     caddr_t        argsp;        /* pointer to args */
  163.     xdrproc_t    xresults;    /* xdr routine for results */
  164.     caddr_t        resultsp;    /* pointer to results */
  165.     struct timeval    utimeout;    /* seconds to wait before giving up */
  166. {
  167.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  168.     register XDR *xdrs;
  169.     register int outlen;
  170.     register int inlen;
  171.     int fromlen;
  172. #ifdef FD_SETSIZE
  173.     fd_set readfds;
  174.     fd_set mask;
  175. #else
  176.     int readfds;
  177.     register int mask;
  178. #endif /* def FD_SETSIZE */
  179.     struct sockaddr_in from;
  180.     struct rpc_msg reply_msg;
  181.     XDR reply_xdrs;
  182.     struct timeval time_waited;
  183.     bool_t ok;
  184.     int nrefreshes = 2;    /* number of times to refresh cred */
  185.     struct timeval timeout;
  186.  
  187.     if (cu->cu_total.tv_usec == -1) {
  188.         timeout = utimeout;     /* use supplied timeout */
  189.     } else {
  190.         timeout = cu->cu_total; /* use default timeout */
  191.     }
  192.  
  193.     time_waited.tv_sec = 0;
  194.     time_waited.tv_usec = 0;
  195. call_again:
  196.     xdrs = &(cu->cu_outxdrs);
  197.     xdrs->x_op = XDR_ENCODE;
  198.     XDR_SETPOS(xdrs, cu->cu_xdrpos);
  199.     /*
  200.      * the transaction is the first thing in the out buffer
  201.      */
  202.     (*(u_short *)(cu->cu_outbuf))++;
  203.     if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  204.         (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  205.         (! (*xargs)(xdrs, argsp)))
  206.         return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  207.     outlen = (int)XDR_GETPOS(xdrs);
  208.  
  209. send_again:
  210.     if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  211.         (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  212.         != outlen) {
  213.         cu->cu_error.re_errno = errno;
  214.         return (cu->cu_error.re_status = RPC_CANTSEND);
  215.     }
  216.  
  217.     /*
  218.      * Hack to provide rpc-based message passing
  219.      */
  220.     if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  221.         return (cu->cu_error.re_status = RPC_TIMEDOUT);
  222.     }
  223.     /*
  224.      * sub-optimal code appears here because we have
  225.      * some clock time to spare while the packets are in flight.
  226.      * (We assume that this is actually only executed once.)
  227.      */
  228.     reply_msg.acpted_rply.ar_verf = _null_auth;
  229.     reply_msg.acpted_rply.ar_results.where = resultsp;
  230.     reply_msg.acpted_rply.ar_results.proc = xresults;
  231. #ifdef FD_SETSIZE
  232.     FD_ZERO(&mask);
  233.     FD_SET(cu->cu_sock, &mask);
  234. #else
  235.     mask = 1 << cu->cu_sock;
  236. #endif /* def FD_SETSIZE */
  237.     for (;;) {
  238.         readfds = mask;
  239.         switch (select(_rpc_dtablesize(), &readfds, (int *)NULL, 
  240.                    (int *)NULL, &(cu->cu_wait))) {
  241.  
  242.         case 0:
  243.             time_waited.tv_sec += cu->cu_wait.tv_sec;
  244.             time_waited.tv_usec += cu->cu_wait.tv_usec;
  245.             while (time_waited.tv_usec >= 1000000) {
  246.                 time_waited.tv_sec++;
  247.                 time_waited.tv_usec -= 1000000;
  248.             }
  249.             if ((time_waited.tv_sec < timeout.tv_sec) ||
  250.                 ((time_waited.tv_sec == timeout.tv_sec) &&
  251.                 (time_waited.tv_usec < timeout.tv_usec)))
  252.                 goto send_again;    
  253.             return (cu->cu_error.re_status = RPC_TIMEDOUT);
  254.  
  255.         /*
  256.          * buggy in other cases because time_waited is not being
  257.          * updated.
  258.          */
  259.         case -1:
  260.             if (errno == EINTR)
  261.                 continue;    
  262.             cu->cu_error.re_errno = errno;
  263.             return (cu->cu_error.re_status = RPC_CANTRECV);
  264.         }
  265.         do {
  266.             fromlen = sizeof(struct sockaddr);
  267.             inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
  268.                 (int) cu->cu_recvsz, 0,
  269.                 (struct sockaddr *)&from, &fromlen);
  270.         } while (inlen < 0 && errno == EINTR);
  271.         if (inlen < 0) {
  272.             if (errno == EWOULDBLOCK)
  273.                 continue;    
  274.             cu->cu_error.re_errno = errno;
  275.             return (cu->cu_error.re_status = RPC_CANTRECV);
  276.         }
  277.         if (inlen < sizeof(u_long))
  278.             continue;    
  279.         /* see if reply transaction id matches sent id */
  280.         if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  281.             continue;    
  282.         /* we now assume we have the proper reply */
  283.         break;
  284.     }
  285.  
  286.     /*
  287.      * now decode and validate the response
  288.      */
  289.     xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  290.     ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  291.     /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  292.     if (ok) {
  293.         _seterr_reply(&reply_msg, &(cu->cu_error));
  294.         if (cu->cu_error.re_status == RPC_SUCCESS) {
  295.             if (! AUTH_VALIDATE(cl->cl_auth,
  296.                 &reply_msg.acpted_rply.ar_verf)) {
  297.                 cu->cu_error.re_status = RPC_AUTHERROR;
  298.                 cu->cu_error.re_why = AUTH_INVALIDRESP;
  299.             }
  300.             if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  301.                 xdrs->x_op = XDR_FREE;
  302.                 (void)xdr_opaque_auth(xdrs,
  303.                     &(reply_msg.acpted_rply.ar_verf));
  304.             } 
  305.         }  /* end successful completion */
  306.         else {
  307.             /* maybe our credentials need to be refreshed ... */
  308.             if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
  309.                 nrefreshes--;
  310.                 goto call_again;
  311.             }
  312.         }  /* end of unsuccessful completion */
  313.     }  /* end of valid reply message */
  314.     else {
  315.         cu->cu_error.re_status = RPC_CANTDECODERES;
  316.     }
  317.     return (cu->cu_error.re_status);
  318. }
  319.  
  320. static void
  321. clntudp_geterr(cl, errp)
  322.     CLIENT *cl;
  323.     struct rpc_err *errp;
  324. {
  325.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  326.  
  327.     *errp = cu->cu_error;
  328. }
  329.  
  330.  
  331. static bool_t
  332. clntudp_freeres(cl, xdr_res, res_ptr)
  333.     CLIENT *cl;
  334.     xdrproc_t xdr_res;
  335.     caddr_t res_ptr;
  336. {
  337.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  338.     register XDR *xdrs = &(cu->cu_outxdrs);
  339.  
  340.     xdrs->x_op = XDR_FREE;
  341.     return ((*xdr_res)(xdrs, res_ptr));
  342. }
  343.  
  344. static void 
  345. clntudp_abort(/*h*/)
  346.     /*CLIENT *h;*/
  347. {
  348. }
  349.  
  350. static bool_t
  351. clntudp_control(cl, request, info)
  352.     CLIENT *cl;
  353.     int request;
  354.     char *info;
  355. {
  356.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  357.  
  358.     switch (request) {
  359.     case CLSET_TIMEOUT:
  360.         cu->cu_total = *(struct timeval *)info;
  361.         break;
  362.     case CLGET_TIMEOUT:
  363.         *(struct timeval *)info = cu->cu_total;
  364.         break;
  365.     case CLSET_RETRY_TIMEOUT:
  366.         cu->cu_wait = *(struct timeval *)info;
  367.         break;
  368.     case CLGET_RETRY_TIMEOUT:
  369.         *(struct timeval *)info = cu->cu_wait;
  370.         break;
  371.     case CLGET_SERVER_ADDR:
  372.         *(struct sockaddr_in *)info = cu->cu_raddr;
  373.         break;
  374.     default:
  375.         return (FALSE);
  376.     }
  377.     return (TRUE);
  378. }
  379.     
  380. static void
  381. clntudp_destroy(cl)
  382.     CLIENT *cl;
  383. {
  384.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  385.  
  386.     if (cu->cu_closeit) {
  387.         (void)close(cu->cu_sock);
  388.     }
  389.     XDR_DESTROY(&(cu->cu_outxdrs));
  390.     mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  391.     mem_free((caddr_t)cl, sizeof(CLIENT));
  392. }
  393.  
  394. static CLIENT *sendrpc_create(raddr, program, version, wait, sockp)
  395.     struct sockaddr_in *raddr;
  396.     u_long program;
  397.     u_long version;
  398.     struct timeval wait;
  399.     register int *sockp;
  400. {
  401.     u_int sendsz = UDPMSGSIZE;
  402.     u_int recvsz = UDPMSGSIZE;
  403.     CLIENT *cl;
  404.     register struct cu_data *cu;
  405.     struct timeval now;
  406.     struct rpc_msg call_msg;
  407.  
  408.     cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  409.     if (cl == NULL) {
  410.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  411.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  412.         rpc_createerr.cf_error.re_errno = errno;
  413.         goto fooy;
  414.     }
  415.     sendsz = ((sendsz + 3) / 4) * 4;
  416.     recvsz = ((recvsz + 3) / 4) * 4;
  417.     cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  418.     if (cu == NULL) {
  419.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  420.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  421.         rpc_createerr.cf_error.re_errno = errno;
  422.         goto fooy;
  423.     }
  424.     cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  425.  
  426.     (void)gettimeofday(&now, (struct timezone *)0);
  427.     if (raddr->sin_port == 0) {
  428.         u_short port;
  429.         if ((port =
  430.             sendrpc_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
  431.             goto fooy;
  432.         }
  433.         raddr->sin_port = htons(port);
  434.     }
  435.     cl->cl_ops = &udp_ops;
  436.     cl->cl_private = (caddr_t)cu;
  437.     cu->cu_raddr = *raddr;
  438.     cu->cu_rlen = sizeof (cu->cu_raddr);
  439.     cu->cu_wait = wait;
  440.     cu->cu_total.tv_sec = -1;
  441.     cu->cu_total.tv_usec = -1;
  442.     cu->cu_sendsz = sendsz;
  443.     cu->cu_recvsz = recvsz;
  444.     call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
  445.     call_msg.rm_direction = CALL;
  446.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  447.     call_msg.rm_call.cb_prog = program;
  448.     call_msg.rm_call.cb_vers = version;
  449.     xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  450.         sendsz, XDR_ENCODE);
  451.     if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  452.         goto fooy;
  453.     }
  454.     cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  455.     if (*sockp < 0) {
  456.         int dontblock = 1;
  457.  
  458.         *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  459.         if (*sockp < 0) {
  460.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  461.             rpc_createerr.cf_error.re_errno = errno;
  462.             goto fooy;
  463.         }
  464.         /* attempt to bind to prov port */
  465.         (void)bindresvport(*sockp, (struct sockaddr_in *)0);
  466.         /* the sockets rpc controls are non-blocking */
  467.         (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
  468.         cu->cu_closeit = TRUE;
  469.     } else {
  470.         cu->cu_closeit = FALSE;
  471.     }
  472.     cu->cu_sock = *sockp;
  473.     cl->cl_auth = authnone_create();
  474.     return (cl);
  475. fooy:
  476.     if (cu)
  477.         mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  478.     if (cl)
  479.         mem_free((caddr_t)cl, sizeof(CLIENT));
  480.     return ((CLIENT *)NULL);
  481. }
  482.  
  483. static struct callrpc_private {
  484.     CLIENT    *client;
  485.     int    socket;
  486.     int    oldprognum, oldversnum, valid;
  487.     char    *oldhost;
  488. } *callrpc_private;
  489.  
  490. sendrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
  491.     char *host;
  492.     xdrproc_t inproc, outproc;
  493.     char *in, *out;
  494. {
  495.     register struct callrpc_private *crp = callrpc_private;
  496.     struct sockaddr_in server_addr;
  497.     enum clnt_stat clnt_stat;
  498.     struct hostent *hp;
  499.     struct timeval timeout, tottimeout, noDefault;
  500.  
  501.     noDefault.tv_sec = 0; noDefault.tv_usec = -1;
  502.     if (crp == 0) {
  503.         crp = (struct callrpc_private *)calloc(1, sizeof (*crp));
  504.         if (crp == 0)
  505.             return (0);
  506.         callrpc_private = crp;
  507.     }
  508.     if (crp->oldhost == NULL) {
  509.         crp->oldhost = (char *)malloc(256);
  510.         crp->oldhost[0] = 0;
  511.         crp->socket = RPC_ANYSOCK;
  512.     }
  513.     if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum
  514.         && strcmp(crp->oldhost, host) == 0) {
  515.         /* reuse old client */        
  516.     } else {
  517.         crp->valid = 0;
  518.         (void)close(crp->socket);
  519.         crp->socket = RPC_ANYSOCK;
  520.         if (crp->client) {
  521.             clnt_destroy(crp->client);
  522.             crp->client = NULL;
  523.         }
  524.         if ((hp = gethostbyname(host)) == NULL) {   /* is address? */
  525.             return ((int) RPC_UNKNOWNHOST);
  526.         } else {
  527.              memcpy((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length);
  528.          }
  529.         timeout.tv_usec = 0;
  530.         timeout.tv_sec = 5;
  531.         server_addr.sin_family = AF_INET;
  532.         server_addr.sin_port =  0;
  533.         if ((crp->client = sendrpc_create(&server_addr, (u_long)prognum,
  534.             (u_long)versnum, timeout, &crp->socket)) == NULL)
  535.             return ((int) rpc_createerr.cf_stat);
  536.         if (!clnt_control(crp->client,CLSET_TIMEOUT,&noDefault)) 
  537.             return ((int) RPC_FAILED);
  538.         crp->valid = 1;
  539.         crp->oldprognum = prognum;
  540.         crp->oldversnum = versnum;
  541.         (void) strcpy(crp->oldhost, host);
  542.     }
  543.     tottimeout.tv_sec = 
  544.     tottimeout.tv_usec = 0;
  545.     clnt_stat = clnt_call(crp->client, procnum, inproc, in,
  546.         outproc, out, tottimeout);
  547.     /* 
  548.      * if call failed, empty cache
  549.      */
  550.     if (clnt_stat == RPC_TIMEDOUT)
  551.         clnt_stat = RPC_SUCCESS;
  552.     if (clnt_stat != RPC_SUCCESS)
  553.         crp->valid = 0;
  554.     return ((int) clnt_stat);
  555. }
  556.